﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;

namespace CharacterCreation.Web.Models {
    public partial class BaseModel {
        public Guid Id { get; set; }
        public string CreatedBy { get; set; }
        public DateTime? DateCreated { get; set; }
        public string ModifiedBy { get; set; }
        public DateTime? DateModified { get; set; }
    }

    public class BaseContentItem : BaseModel {
        public string Name { get; set; }
        public string DisplayName { get; set; }
        [DataType(DataType.Html)]
        public string Description { get; set; } 
        public string Key { get; set; }
        public string GroupKey { get; set; }
    }

    public interface ICalculatoryModel {
        ICollection<XPDetail> XPDetails { get; set; }
        ICollection<BonusDetail> BonusDetails { get; set; }
        void Calculate();
    }

    public partial class Player : BaseContentItem {
        public string Email { get; set; }
        public int MyProperty { get; set; }
        public ICollection<Character> Characters { get; set; }

        public Player() {
            this.Characters = new HashSet<Character>();
        }
    }

    public partial class Character : BaseContentItem {
        public DateTime CreationDate { get; set; }
        public string ImageUrl { get; set; }

        public virtual CharacterStrength Strength { get; set; }
        public virtual CharacterDexterity Dexterity { get; set; }
        public virtual CharacterFighting Fighting { get; set; }
        public virtual CharacterConstitution Constitution { get; set; }
        public virtual CharacterPerception Perception { get; set; }
        public virtual CharacterIntelligence Intelligence { get; set; }
        public virtual CharacterWillPower WillPower { get; set; }
        public virtual CharacterCharisma Charisma { get; set; }
        public virtual CharacterHitPoints HitPoints { get; set; }
        public virtual CharacterEssence Essence { get; set; }

        public virtual Race Race { get; set; }
        public virtual Profession Profession { get; set; }

        public virtual ICollection<CharacterSkill> Skills { get; set; }
        public virtual ICollection<CharacterSpecial> Specials { get; set; }
        public virtual ICollection<CharacterEnergy> Energies { get; set; }
        public virtual ICollection<CharacterSpell> Spells { get; set; }
        public virtual ICollection<CharacterEquipment> Equipment { get; set; }
        public virtual ICollection<Note> Notes { get; set; }

        public Character() {
            this.Skills = new HashSet<CharacterSkill>();
            this.Specials = new HashSet<CharacterSpecial>();
            this.Energies = new HashSet<CharacterEnergy>();
            this.Spells = new HashSet<CharacterSpell>();
            this.Equipment = new HashSet<CharacterEquipment>();
            this.Notes = new HashSet<Note>();
        }
    }

    public partial class BaseStatistic : BaseContentItem, ICalculatoryModel {
        public int Rolled { get; set; }
        public int Moved { get; set; }
        public int RaceBonus { get; set; }
        public int ProfBonus { get; set; }
        public int Level { get; set; }
        public int TotalBonus { get { return RaceBonus + ProfBonus + (BonusDetails != null ? BonusDetails.Sum(b => b.Bonus) : 0); } }
        public int TotalXP {
            get { return (XPDetails != null ? XPDetails.Sum(x => x.XP) : 0) + (BonusDetails != null ? BonusDetails.Sum(b => b.XPValue) : 0); }
        }
        public int TotalLevel { get { return Level + TotalBonus; } }
        public virtual ICollection<XPDetail> XPDetails { get; set; }
        public virtual ICollection<BonusDetail> BonusDetails { get; set; }
        public virtual Type StatisticType { get { return null; } }
        public virtual void Calculate() {
            if (this.XPDetails == null) this.XPDetails = new HashSet<XPDetail>();
            if (this.BonusDetails == null) this.BonusDetails = new HashSet<BonusDetail>();
            var statistic = Moved != 0 ? Moved : Rolled;
            this.Level = LevelCalculations.CalculateStatistic(statistic, XPDetails != null ? XPDetails.Sum(x => x.XP) : 0);
        }
        public BaseStatistic() {
            this.XPDetails = new HashSet<XPDetail>();
            this.BonusDetails = new HashSet<BonusDetail>();
        }
    }

    public partial class CharacterStrength : BaseStatistic {
        public int DamageAdjustment { get; set; }
        public int WeightAllowance { get; set; }
        public int InternalStrengthAdjustment { get; set; }

        /// <summary>
        /// Return the type of the statistic you want to do calcualtions on
        /// </summary>
        public override Type StatisticType {
            get { return typeof(Strength); }
        }

        public override void Calculate() {
            base.Calculate();
            var strength = new CharacterContext().Strengths.FirstOrDefault(s => s.Level == this.TotalLevel);
            if (strength != null) {
                this.Description = string.Format("DA:{0}, WA:{1}, IS:{2}", strength.DamageAdjustment, strength.WeightAllowance, strength.InternalStrengthAdjustment);
                this.DamageAdjustment = strength.DamageAdjustment;
                this.WeightAllowance = strength.WeightAllowance;
                this.InternalStrengthAdjustment = strength.InternalStrengthAdjustment;
            }
            else {
                this.Description = "Out of bounds";
            }
        }
    }

    public partial class Strength : BaseModel {
        public int Level { get; set; }
        public string Description { get; set; }
        public int DamageAdjustment { get; set; }
        public int WeightAllowance { get; set; }
        public int InternalStrengthAdjustment { get; set; }
    }

    public partial class CharacterDexterity : BaseStatistic {
        public int InitiativeModifier { get; set; }
        public int CombatPenalty { get; set; }

        /// <summary>
        /// Return the type of the statistic you want to do calcualtions on
        /// </summary>
        public override Type StatisticType {
            get { return typeof(Dexterity); }
        }

        public override void Calculate() {
            base.Calculate();
            var dex = new CharacterContext().Dexterities.FirstOrDefault(s => s.Level == this.TotalLevel);
            if (dex != null) {
                this.Description = string.Format("IM:{0}, CP:{1}", dex.InitiativeModifier, dex.CombatPenalty);
                this.InitiativeModifier = dex.InitiativeModifier;
                this.CombatPenalty = dex.CombatPenalty;
            }
            else {
                this.Description = "Out of bounds";
            }
        }
    }

    public partial class Dexterity : BaseModel {
        public int Level { get; set; }
        public string Description { get; set; }
        public int InitiativeModifier { get; set; }
        public int CombatPenalty { get; set; }
    }

    public partial class CharacterFighting : BaseStatistic {
        public int CombatPenalty { get; set; }
        public int WeaponPenalty { get; set; }

        /// <summary>
        /// Return the type of the statistic you want to do calcualtions on
        /// </summary>
        public override Type StatisticType {
            get { return typeof(Fighting); }
        }

        public override void Calculate() {
            base.Calculate();
            var fig = new CharacterContext().Fightings.FirstOrDefault(s => s.Level == this.TotalLevel);
            if (fig != null) {
                this.Description = string.Format("CP:{0}, WP:{1}", fig.CombatPenalty, fig.WeaponPenalty);
                this.CombatPenalty = fig.CombatPenalty;
                this.WeaponPenalty = fig.WeaponPenalty;
            }
            else {
                this.Description = "Out of bounds";
            }
        }
    }

    public partial class Fighting : BaseModel {
        public int Level { get; set; }
        public string Description { get; set; }
        public int CombatPenalty { get; set; }
        public int WeaponPenalty { get; set; }
    }

    public partial class CharacterConstitution : BaseStatistic {
        public int BeginningHitpointAdjustment { get; set; }
        public double HealingRate { get; set; }
        public int ResistanceToPoison { get; set; }
        public int ResistanceToDisease { get; set; }

        /// <summary>
        /// Return the type of the statistic you want to do calcualtions on
        /// </summary>
        public override Type StatisticType {
            get { return typeof(Constitution); }
        }

        public override void Calculate() {
            base.Calculate();
            var con = new CharacterContext().Constitutions.FirstOrDefault(s => s.Level == this.TotalLevel);
            if (con != null) {
                this.Description = string.Format(
                    "BHPA:{0}, HR:{1}, RTP:{2}, RTD:{3}",
                    con.BeginningHitpointAdjustment,
                    con.HealingRate,
                    con.ResistanceToPoison,
                    con.ResistanceToDisease);
                this.BeginningHitpointAdjustment = con.BeginningHitpointAdjustment;
                this.HealingRate = con.HealingRate;
                this.ResistanceToPoison = con.ResistanceToPoison;
                this.ResistanceToDisease = con.ResistanceToDisease;
            }
            else {
                this.Description = "Out of bounds";
            }
        }
    }

    public partial class Constitution : BaseModel {
        public int Level { get; set; }
        public string Description { get; set; }
        public int BeginningHitpointAdjustment { get; set; }
        public double HealingRate { get; set; }
        public int ResistanceToPoison { get; set; }
        public int ResistanceToDisease { get; set; }
    }

    public partial class CharacterPerception : BaseStatistic {
        public int RangeAdjustment { get; set; }

        /// <summary>
        /// Return the type of the statistic you want to do calcualtions on
        /// </summary>
        public override Type StatisticType {
            get { return typeof(Perception); }
        }

        public override void Calculate() {
            base.Calculate();
            var per = new CharacterContext().Perceptions.FirstOrDefault(s => s.Level == this.TotalLevel);
            if (per != null) {
                this.Description = string.Format("RA:{0}", per.RangeAdjustment);
                this.RangeAdjustment = per.RangeAdjustment;
            }
            else {
                this.Description = "Out of bounds";
            }
        }
    }

    public partial class Perception : BaseModel {
        public int Level { get; set; }
        public string Description { get; set; }
        public int RangeAdjustment { get; set; }
    }

    public partial class CharacterIntelligence : BaseStatistic {
        public int SkillAdjustment { get; set; }
        public int ExperienceAdjustment { get; set; }

        /// <summary>
        /// Return the type of the statistic you want to do calcualtions on
        /// </summary>
        public override Type StatisticType {
            get { return typeof(Intelligence); }
        }

        public override void Calculate() {
            base.Calculate();
            var intelligence = new CharacterContext().Intelligences.FirstOrDefault(s => s.Level == this.TotalLevel);
            if (intelligence != null) {
                this.Description = string.Format("XPA:{0}, SA:{1}", intelligence.ExperienceAdjustment, intelligence.SkillAdjustment);
                this.SkillAdjustment = intelligence.SkillAdjustment;
                this.ExperienceAdjustment = intelligence.ExperienceAdjustment;
            }
            else {
                this.Description = "Out of bounds";
            }
        }
    }

    public partial class Intelligence : BaseModel {
        public int Level { get; set; }
        public string Description { get; set; }
        public int ExperienceAdjustment { get; set; }
        public int SkillAdjustment { get; set; }
    }


    public partial class CharacterWillPower : BaseStatistic {
        public int BeginningEssenceAdjustment { get; set; }
        public double EssenceHealingRate { get; set; }

        /// <summary>
        /// Return the type of the statistic you want to do calcualtions on
        /// </summary>
        public override Type StatisticType {
            get { return typeof(WillPower); }
        }

        public override void Calculate() {
            base.Calculate();
            var will = new CharacterContext().WillPowers.FirstOrDefault(s => s.Level == this.TotalLevel);
            if (will != null) {
                this.Description = string.Format("BEA:{0}", will.BeginningEssenceAdjustment);
                this.BeginningEssenceAdjustment = will.BeginningEssenceAdjustment;
                this.EssenceHealingRate = will.EssenceHealingRate;
            }
            else {
                this.Description = "Out of bounds";
            }
        }
    }

    public partial class WillPower : BaseModel {
        public int Level { get; set; }
        public string Description { get; set; }
        public int BeginningEssenceAdjustment { get; set; }
        public double EssenceHealingRate { get; set; }
    }

    public partial class CharacterCharisma : BaseStatistic {
        public int AppearanceAdjustment { get; set; }

        /// <summary>
        /// Return the type of the statistic you want to do calcualtions on
        /// </summary>
        public override Type StatisticType {
            get { return typeof(Charisma); }
        }

        public override void Calculate() {
            base.Calculate();
            var cha = new CharacterContext().Charismas.FirstOrDefault(s => s.Level == this.TotalLevel);
            if (cha != null) {
                this.Description = string.Format("AA:{0}", cha.AppearanceAdjustment);
                this.AppearanceAdjustment = cha.AppearanceAdjustment;
            }
            else {
                this.Description = "Out of bounds";
            }
        }
    }

    public partial class Charisma : BaseModel {
        public int Level { get; set; }
        public string Description { get; set; }
        public int AppearanceAdjustment { get; set; }
    }


    public partial class CharacterHitPoints : BaseStatistic {
        public override void Calculate() {
            if (this.XPDetails == null) this.XPDetails = new HashSet<XPDetail>();
            if (this.BonusDetails == null) this.BonusDetails = new HashSet<BonusDetail>();
            var statistic = Moved != 0 ? Moved : Rolled;
            var _level = LevelCalculations.CalculateHpAndEssence(statistic, XPDetails != null ? XPDetails.Sum(x => x.XP) : 0);
            var _bonus = BonusDetails != null ? BonusDetails.Sum(b => b.Bonus) : 0;

            if (CharacterService.Instance.SelectedCharacter != null)
                _bonus += CharacterService.Instance.SelectedCharacter.Constitution.BeginningHitpointAdjustment;

            this.Level = _level + _bonus;
        }
    }

    public partial class CharacterEssence : BaseStatistic {
        public override void Calculate() {
            if (this.XPDetails == null) this.XPDetails = new HashSet<XPDetail>();
            if (this.BonusDetails == null) this.BonusDetails = new HashSet<BonusDetail>();
            var statistic = Moved != 0 ? Moved : Rolled;
            var _level = LevelCalculations.CalculateHpAndEssence(statistic, XPDetails != null ? XPDetails.Sum(x => x.XP) : 0);
            var _bonus = BonusDetails != null ? BonusDetails.Sum(b => b.Bonus) : 0;

            if (CharacterService.Instance.SelectedCharacter != null)
                _bonus += CharacterService.Instance.SelectedCharacter.WillPower.BeginningEssenceAdjustment;

            this.Level = _level + _bonus;
        }
    }

    public partial class CharacterSkill : BaseContentItem, ICalculatoryModel {
        public string Notes { get; set; }
        public int Statistic { get; set; }
        private int _Statistic;
        public string Statistics { get; set; }
        public int RaceBonus { get; set; }
        public int ProfBonus { get; set; }
        public string Source { get; set; }
        public int SourceXP { get; set; }
        public string SkillType { get; set; }
        public string ImageUrl { get; set; }
        public int Level { get; set; }
        public int TotalBonus { get { return RaceBonus + ProfBonus + (BonusDetails != null ? BonusDetails.Sum(b => b.Bonus) : 0); } }
        public int TotalXP { get { return (XPDetails != null ? XPDetails.Sum(x => x.XP) : 0) + (BonusDetails != null ? BonusDetails.Sum(b => b.XPValue) : 0); } }
        public int TotalLevel { get { return Level + TotalBonus; } }

        public virtual ICollection<XPDetail> XPDetails { get; set; }
        public virtual ICollection<BonusDetail> BonusDetails { get; set; }

        public virtual void Calculate() {
            if (this.XPDetails == null) this.XPDetails = new HashSet<XPDetail>();
            if (this.BonusDetails == null) this.BonusDetails = new HashSet<BonusDetail>();
            this.Level = LevelCalculations.CalculateSkill(Statistic, XPDetails != null ? XPDetails.Sum(x => x.XP) : 0);
        }

        public CharacterSkill() {
            this.XPDetails = new HashSet<XPDetail>();
            this.BonusDetails = new HashSet<BonusDetail>();
        }
    }

    public partial class Skill : BaseContentItem {
        public string Statistics { get; set; }
        public string ImageUrl { get; set; }
        public int XPCost { get; set; }
        public string SkillType { get; set; }
    }

    public partial class CharacterSpecial : BaseContentItem, ICalculatoryModel {
        public string Notes { get; set; }
        public int Statistic { get; set; }
        public string Statistics { get; set; }
        public int RaceBonus { get; set; }
        public int ProfBonus { get; set; }
        public string Source { get; set; }
        public int SourceXP { get; set; }
        public int PriorityPointCost { get; set; }
        public string Key { get; set; }
        public string ImageUrl { get; set; }
        public int Level { get; set; }
        public int TotalBonus { get { return RaceBonus + ProfBonus + (BonusDetails != null ? BonusDetails.Sum(b => b.Bonus) : 0); } }
        public int TotalXP { get { return (XPDetails != null ? XPDetails.Sum(x => x.XP) : 0) + (BonusDetails != null ? BonusDetails.Sum(b => b.XPValue) : 0); } }
        public int TotalLevel { get { return Level + TotalBonus; } }

        public virtual ICollection<XPDetail> XPDetails { get; set; }
        public virtual ICollection<BonusDetail> BonusDetails { get; set; }

        public virtual void Calculate() {
            if (this.XPDetails == null) this.XPDetails = new HashSet<XPDetail>();
            if (this.BonusDetails == null) this.BonusDetails = new HashSet<BonusDetail>();
            this.Level = LevelCalculations.CalculateSpecial(Statistic, XPDetails != null ? XPDetails.Sum(x => x.XP) : 0);
        }

        public CharacterSpecial() {
            this.XPDetails = new HashSet<XPDetail>();
            this.BonusDetails = new HashSet<BonusDetail>();
        }
    }

    public partial class Special : BaseContentItem {
        public string Statistics { get; set; }
        public string ImageUrl { get; set; }
    }

    public partial class CharacterEnergy : BaseContentItem, ICalculatoryModel {
        public string Notes { get; set; }
        public int Statistic { get; set; }
        public string Statistics { get; set; }
        public int RaceBonus { get; set; }
        public int ProfBonus { get; set; }
        public string Source { get; set; }
        public int SourceXP { get; set; }
        public string Key { get; set; }
        public string ImageUrl { get; set; }
        public int Level { get; set; }
        public int TotalBonus { get { return RaceBonus + ProfBonus + (BonusDetails != null ? BonusDetails.Sum(b => b.Bonus) : 0); } }
        public int TotalXP { get { return (XPDetails != null ? XPDetails.Sum(x => x.XP) : 0) + (BonusDetails != null ? BonusDetails.Sum(b => b.XPValue) : 0); } }
        public int TotalLevel { get { return Level + TotalBonus; } }

        public virtual ICollection<XPDetail> XPDetails { get; set; }
        public virtual ICollection<BonusDetail> BonusDetails { get; set; }

        public virtual void Calculate() {
            if (this.XPDetails == null) this.XPDetails = new HashSet<XPDetail>();
            if (this.BonusDetails == null) this.BonusDetails = new HashSet<BonusDetail>();
            int beginvalue = CharacterService.Instance.SelectedCharacter != null ?
                CharacterService.Instance.SelectedCharacter.Essence.TotalLevel :
                Statistic;
            this.Level = LevelCalculations.CalculateEnergy(Statistic, beginvalue, XPDetails != null ? XPDetails.Sum(x => x.XP) : 0);
        }

        public CharacterEnergy() {
            this.XPDetails = new HashSet<XPDetail>();
            this.BonusDetails = new HashSet<BonusDetail>();
        }
    }

    public partial class Energy : BaseContentItem {
        public string Statistics { get; set; }
        public string ImageUrl { get; set; }
    }

    public partial class XPDetail : BaseModel {
        public int XP { get; set; }
        public string Reason { get; set; }
        public string GroupKey { get; set; }
        public string Source { get; set; }
        public string Key { get; set; }
        public DateTime DateXPReceived { get; set; }
    }

    public partial class BonusDetail : BaseModel {
        public int Bonus { get; set; }
        public string Reason { get; set; }
        public string GroupKey { get; set; }
        public int XPValue { get; set; }
        public string Source { get; set; }
        public string Key { get; set; }
        public DateTime DateBonusReceived { get; set; }
    }

    public partial class CharacterEquipment : BaseContentItem {
    }

    public partial class Equipment : BaseContentItem {
    }

    public partial class Note : BaseContentItem {
        public DateTime DateWritten { get; set; }
        public string Text { get; set; }
    }

    public partial class SchoolOfMagic : BaseContentItem {
        public int PriorityPointCost { get; set; }
        public string ImageUrl { get; set; }

        public virtual ICollection<ComponentRow> Components { get; set; }
        public virtual ICollection<Spell> Spells { get; set; }

        public SchoolOfMagic() {
            this.Components = new HashSet<ComponentRow>();
            this.Spells = new HashSet<Spell>();
        }
    }

    public partial class ComponentRow : BaseContentItem {

        public virtual SchoolOfMagic SchoolOfMagic { get; set; }

        public bool Verbal { get; set; }
        public bool Gesture { get; set; }
        public bool Material { get; set; }

        public int SkillToMana { get; set; }
        public int SkillFromMana { get; set; }

        public int InitiativeModifier { get; set; }
        public int QuickSpellInitiativeModifier { get; set; }

        internal static ComponentRow Create() {
            ComponentRow row = new ComponentRow();
            return row;
        }
    }

    public partial class Spell : BaseContentItem {
        public virtual SchoolOfMagic SchoolOfMagic { get; set; }

        public string Notes { get; set; }
        public int DifficultyToLearn { get; set; }
        public int Rank { get; set; }
        public string Category { get; set; }
        public int BaseSkill { get; set; }
        public int BaseMana { get; set; }
        public int SkillPerLevel { get; set; }
        public int ManaPerLevel { get; set; }

        public double RangePerLevel { get; set; }
        public double TargetsPerLevel { get; set; }
        public double DurationPerLevel { get; set; }
        public double AreaPerLevel { get; set; }
        public string DmgPerLevel { get; set; }
        public string DescriptionPerLevel { get; set; }

        public static Spell Create() {
            Spell spell = new Spell();
            spell.Rank = 1;
            spell.DifficultyToLearn = 100;
            spell.DmgPerLevel = "0 d4";
            return spell;
        }
    }

    public partial class CharacterSpell : BaseContentItem, ICalculatoryModel {
        public string Source { get; set; }
        public int SourceXP { get; set; }

        public string Notes { get; set; }
        public int DifficultyToLearn { get; set; }
        public int Rank { get; set; }
        public string Category { get; set; }
        public int BaseSkill { get; set; }
        public int BaseMana { get; set; }
        public int SkillPerLevel { get; set; }
        public int ManaPerLevel { get; set; }

        public double RangePerLevel { get; set; }
        public double TargetsPerLevel { get; set; }
        public double DurationPerLevel { get; set; }
        public double AreaPerLevel { get; set; }
        public string DmgPerLevel { get; set; }
        public string DescriptionPerLevel { get; set; }

        public Guid SchoolOfMagicId { get; set; }

        public ICollection<XPDetail> XPDetails { get; set; }
        public ICollection<BonusDetail> BonusDetails { get; set; }
        public void Calculate() { }

        public CharacterSpell() {
            this.XPDetails = new HashSet<XPDetail>();
            this.BonusDetails = new HashSet<BonusDetail>();
        }
    }

    public partial class Race : BaseContentItem {

        public int StrengthBonus { get; set; }
        public int DexterityBonus { get; set; }
        public int FightingBonus { get; set; }
        public int ConstitutionBonus { get; set; }
        public int PerceptionBonus { get; set; }
        public int IntelligenceBonus { get; set; }
        public int WillPowerBonus { get; set; }
        public int CharismaBonus { get; set; }
        public int HitPointsBonus { get; set; }
        public int EssenceBonus { get; set; }

        public int PriorityPoints { get; set; }
        public int FreeXP { get; set; }

        public Race() {
        }
    }

    public partial class RaceSkill : BaseModel {
        public Skill Skill { get; set; }
        public Race Race { get; set; }
        public bool IsFree { get; set; }
        public int RaceBonus { get; set; }
    }

    public partial class Profession : BaseContentItem {
        
    }
}